package com.sunline.poc.oozie.aop;

import com.sunline.poc.oozie.ApplicationProperties;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(999)
public class OzServiceRetryAspect {
    private Logger logger = LoggerFactory.getLogger(getClass());

    private Object watiObj = new Object();

    @Autowired
    private ApplicationProperties applicationProperties;

    @Pointcut("execution(* com.sunline.poc.oozie.service.impl.OozieServiceImpl.*(..)) ")
    public void point() {
    }

    @Around("point()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

        Object result = null;
        try{
            result = pjp.proceed();
        }catch (Throwable e){
            if (e instanceof  RuntimeException){
                throw  e;
            }
            logger.error("",e);
            result = retry(pjp,1);
        }

        return result;
    }

    /**
     * 重试
     * @param pjp
     * @param retryIndex
     * @return
     */
    public Object  retry(ProceedingJoinPoint pjp,int retryIndex) throws Throwable {
        long retryCount = applicationProperties.getJobRetries();
        long retryDelay = applicationProperties.getJobRetriesDelay();

        if (retryIndex > retryCount){
            throw new RuntimeException("number of retries out of "+retryCount+", shutdown it, check log pleases.");
        }

        try {
            logger.info("reday to retry({}) after {}ms",retryIndex,retryDelay);
            waitDealy(retryDelay);
            return  pjp.proceed();
        } catch (Throwable e) {
            logger.error("retry({}) error ",retryIndex,e);
            retryIndex ++;
            return retry(pjp,retryIndex);
        }

    }

    public  void  waitDealy(long time){
        synchronized (watiObj) {
            try {
                watiObj.wait(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
